#include "DeviceContext.h"
DeviceContext::DeviceContext(
		ID3D11DeviceContext* dc,
		ID3D11RenderTargetView* rtv,
		ID3D11Texture2D* tex,
		ID3D11DepthStencilState* dss,
		ID3D11DepthStencilView* dsv,
		ID3D11RasterizerState* rs,
		DeviceClass* device)
	:Component(COMP_DEVICE_CONTEXT),
	m_deviceContext(dc),
	m_renderTargetView(rtv),
	m_depthStencilBuffer(tex),
	m_depthStencilState(dss),
	m_depthStencilView(dsv),
	m_rasterState(rs),
	m_device(device)
{
}

DeviceContext::~DeviceContext()
{
	if(m_rasterState!=0)
	{
		m_rasterState->Release();
		m_rasterState=0;
	}
	
	if(m_depthStencilView!=0)
	{
		m_depthStencilView->Release();
		m_depthStencilView=0;
	}
	
	if(m_depthStencilState!=0)
	{
		m_depthStencilState->Release();
		m_depthStencilState=0;
	}
	
	if(m_depthStencilBuffer!=0)
	{
		m_depthStencilBuffer->Release();
		m_depthStencilBuffer=0;
	}
	
	if(m_renderTargetView!=0)
	{
		m_renderTargetView->Release();
		m_renderTargetView=0;
	}
		
	if(m_deviceContext!=0)
	{
		m_deviceContext->Release();
		m_deviceContext=0;
	}
}

void DeviceContext::AddedToObject()
{
	RequestMessage(MSG_SET_DSS,&DeviceContext::SetDepthStencilState);
	RequestMessage(MSG_SET_RT,&DeviceContext::SetRenderTargets);
	RequestMessage(MSG_SET_RS,&DeviceContext::SetRasterizerState);
	RequestMessage(MSG_SET_VIEWPORT,&DeviceContext::SetViewports);
	RequestMessage(MSG_CLEAR_RTV,&DeviceContext::ClearRenderTargetView);
	RequestMessage(MSG_CLEAR_DSV,&DeviceContext::ClearDepthStencilView);
	RequestMessage(MSG_SET_BS,&DeviceContext::SetBlendState);
	RequestMessage(MSG_SET_SR_PS,&DeviceContext::PSSetShaderResources);
	RequestMessage(MSG_UPDATE_BUFFER,&DeviceContext::UpdateBuffer);
	RequestMessage(MSG_SET_CB_VS,&DeviceContext::VSSetConstantBuffers);
	RequestMessage(MSG_SET_CB_PS,&DeviceContext::PSSetConstantBuffers);
	RequestMessage(MSG_SET_IL,&DeviceContext::SetInputLayout);
	RequestMessage(MSG_SET_VSS,&DeviceContext::VSSetShader);
	RequestMessage(MSG_SET_PSS,&DeviceContext::PSSetShader);
	RequestMessage(MSG_SET_VB,&DeviceContext::SetVertexBuffers);
	RequestMessage(MSG_SET_IB,&DeviceContext::SetIndexBuffers);
	RequestMessage(MSG_SET_PT,&DeviceContext::SetPrimitiveTopology);
	RequestMessage(MSG_DI,&DeviceContext::DrawIndex);
	RequestMessage(MSG_SET_SAMPLERS_PS,&DeviceContext::PSSetSamplers);
	RequestMessage(MSG_DRAW,&DeviceContext::Draw);
	RequestMessage(MSG_RESET_ALL_STATE,&DeviceContext::Reset);
}

ID3D11DeviceContext* DeviceContext::GetDeviceContext()
{
	return m_deviceContext;
}

void DeviceContext::Reset(const Message& msg)
{
	//m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1);
	m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, NULL);
	m_deviceContext->RSSetState(m_rasterState);
	m_deviceContext->RSSetViewports(1, &m_viewport);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::Reset",err);
}

/*
Should impl test depth stencil in the feature...
second parameter is revelate about this point.
*/
void DeviceContext::SetDepthStencilState(const Message& msg)
{
	ID3D11DepthStencilState* depthStencilState=0;
	AuxUnGroupArgus(msg.p,depthStencilState);
	m_deviceContext->OMSetDepthStencilState(depthStencilState,0);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetDepthStencilState",err);
}

void DeviceContext::UpdateBuffer(const Message& msg)
{
	ID3D11Buffer* buffer;
	void* data;
	size_t size;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	AuxUnGroupArgus(msg.p,buffer,data,size);
	HRESULT hr = m_deviceContext->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	CHECK_FAILED(hr)

	memcpy(mappedResource.pData,data,size);

	// Unlock the matrix constant buffer.
    m_deviceContext->Unmap(buffer, 0);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::UpdateBuffer",err);
}

void DeviceContext::SetRenderTargets(const Message& msg)
{
	std::vector< ID3D11RenderTargetView* > viewList;
	ID3D11DepthStencilView* depthStencilView=0;
	AuxUnGroupArgus(msg.p,viewList,depthStencilView);
	int n=viewList.size();
	if(n==0)
	{
		m_deviceContext->OMSetRenderTargets(0,NULL,depthStencilView);
	}
	else
	{
		m_deviceContext->OMSetRenderTargets(n,&viewList[0],depthStencilView);
	}
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetRenderTargets",err);
}

void DeviceContext::SetRasterizerState(const Message& msg)
{
	ID3D11RasterizerState* rasterizerState=0;
	AuxUnGroupArgus(msg.p,rasterizerState);
	m_deviceContext->RSSetState(rasterizerState);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetRasterizerState",err);
}

void DeviceContext::SetViewports(const Message& msg)
{
	Vector< D3D11_VIEWPORT* > viewports;
	AuxUnGroupArgus(msg.p,viewports);
	int n=viewports.size();
	m_deviceContext->RSSetViewports(n,viewports[0]);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetViewports",err);
}

void DeviceContext::ClearRenderTargetView(const Message& msg)
{
	ID3D11RenderTargetView* targetView=0;
	bool defaultRT;
	float* color;
	AuxUnGroupArgus(msg.p,targetView,color,defaultRT);
	if(defaultRT)
		m_deviceContext->ClearRenderTargetView(m_renderTargetView,color);
	else
		m_deviceContext->ClearRenderTargetView(targetView,color);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::ClearRenderTargetView",err);
}

void DeviceContext::ClearDepthStencilView(const Message& msg)
{
	ID3D11DepthStencilView* depthStencilView=0;
	bool defaultRT;
	D3D11_CLEAR_FLAG flag;
	float depth=0;
	UINT8 stencil=0;
	AuxUnGroupArgus(msg.p,depthStencilView,flag,depth,stencil,defaultRT);
	if(defaultRT)
		m_deviceContext->ClearDepthStencilView(m_depthStencilView,flag,depth,stencil);
	else
		m_deviceContext->ClearDepthStencilView(depthStencilView,flag,depth,stencil);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::ClearDepthStencilView",err);
}

void DeviceContext::SetBlendState(const Message& msg)
{
	ID3D11BlendState* blendState=0;
	float* blendFactor=0;
	unsigned int sampleMask=0;
	AuxUnGroupArgus(msg.p,blendState,blendFactor,sampleMask);
	m_deviceContext->OMSetBlendState(blendState,blendFactor,sampleMask);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetBlendState",err);
}

void DeviceContext::PSSetShaderResources(const Message& msg)
{
	unsigned int startSlot=0;
	unsigned int numViews=0;
	ID3D11ShaderResourceView* shaderResourceView=0;
	AuxUnGroupArgus(msg.p,startSlot,numViews,shaderResourceView);
	m_deviceContext->PSGetShaderResources(startSlot,numViews,&shaderResourceView);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::PSSetShaderResources",err);
}

void DeviceContext::VSSetConstantBuffers(const Message& msg)
{
	unsigned int startSlot=0;
	unsigned int numViews=0;
	ID3D11Buffer* buffer=0;
	AuxUnGroupArgus(msg.p,startSlot,numViews,buffer);
	m_deviceContext->VSSetConstantBuffers(startSlot,numViews,&buffer);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::VSSetConstantBuffers",err);
}

void DeviceContext::PSSetConstantBuffers(const Message& msg)
{
	unsigned int startSlot=0;
	unsigned int numViews=0;
	ID3D11Buffer* buffer=0;
	AuxUnGroupArgus(msg.p,startSlot,numViews,buffer);
	m_deviceContext->PSSetConstantBuffers(startSlot,numViews,&buffer);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::PSSetConstantBuffers",err);
}

void DeviceContext::SetInputLayout(const Message& msg)
{
	ID3D11InputLayout* inputLayout=0;
	AuxUnGroupArgus(msg.p,inputLayout);
	m_deviceContext->IASetInputLayout(inputLayout);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetInputLayout",err);
}

void DeviceContext::VSSetShader(const Message& msg)
{
	ID3D11VertexShader* vertexShader=0;
	std::vector<ID3D11ClassInstance*> classInstances;
	AuxUnGroupArgus(msg.p,vertexShader,classInstances);
	unsigned int numInstances=classInstances.size();
	if(numInstances==0)
		m_deviceContext->VSSetShader(vertexShader,NULL,0);
	else
		m_deviceContext->VSSetShader(vertexShader,&classInstances[0],numInstances);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::VSSetShader",err);
}

void DeviceContext::PSSetShader(const Message& msg)
{
	ID3D11PixelShader* pixelShader=0;
	std::vector<ID3D11ClassInstance*> classInstances;
	AuxUnGroupArgus(msg.p,pixelShader,classInstances);
	unsigned int numInstances=classInstances.size();
	if(numInstances==0)
		m_deviceContext->PSSetShader(pixelShader,NULL,0);
	else
		m_deviceContext->PSSetShader(pixelShader,&classInstances[0],numInstances);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::PSSetShader",err);
}

void DeviceContext::SetVertexBuffers(const Message& msg)
{
	int startSlot=0;
	int numBuffers=0;
	ID3D11Buffer* buffer=0;
	unsigned int* pStrides=0;
	unsigned int* pOffsets=0;
	AuxUnGroupArgus(msg.p,startSlot,numBuffers,buffer,pStrides,pOffsets);
	m_deviceContext->IASetVertexBuffers(startSlot,numBuffers,&buffer,pStrides,pOffsets);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetVertexBuffers",err);
}

void DeviceContext::SetIndexBuffers(const Message& msg)
{
	ID3D11Buffer* buffer=0;
	DXGI_FORMAT format;
	unsigned int offset=0;
	
	AuxUnGroupArgus(msg.p,buffer,format,offset);
	m_deviceContext->IASetIndexBuffer(buffer,format,offset);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetIndexBuffers",err);
}

void DeviceContext::SetPrimitiveTopology(const Message& msg)
{
	D3D11_PRIMITIVE_TOPOLOGY pt;
	AuxUnGroupArgus(msg.p,pt);
	m_deviceContext->IASetPrimitiveTopology(pt);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::SetPrimitiveTopology",err);
}

void DeviceContext::DrawIndex(const Message& msg)
{
	unsigned int indexCount=0;
	unsigned int startIndexLocation=0;
	int baseVertexLocation=0;
	AuxUnGroupArgus(msg.p,indexCount,startIndexLocation,baseVertexLocation);
	m_deviceContext->DrawIndexed(indexCount,startIndexLocation,baseVertexLocation);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::DrawIndex",err);
}

void DeviceContext::PSSetSamplers(const Message& msg)
{
	unsigned int startSlot=0;
	unsigned int numSamplers=0;
	ID3D11SamplerState* samplerState=0;
	AuxUnGroupArgus(msg.p,startSlot,numSamplers,samplerState);
	m_deviceContext->PSSetSamplers(startSlot,numSamplers,&samplerState);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::PSSetSamplers",err);
}

void DeviceContext::Draw(const Message& msg)
{
	int count;
	int offset;
	AuxUnGroupArgus(msg.p,count,offset);
	m_deviceContext->Draw(count,offset);
	string err=m_device->DetectError();
	if(err!="")
		DX11_EXCEPTION("DeviceContext::Draw",err);
}

//struct SimpleVertex
//{
//	XMFLOAT3 Pos;
//};
//
//ID3D11Buffer*           g_pVertexBuffer = NULL;
//ID3D11Buffer*           g_pIndexBuffer = NULL;
//
//void DeviceContext::TestInit(const Message& msg)
//{
//
//    // Create vertex buffer
//    SimpleVertex vertices[] =
//    {
//        { XMFLOAT3( -1.0f, 1.0f, -1.0f ) },
//        { XMFLOAT3( 1.0f, 1.0f, -1.0f ) },
//        { XMFLOAT3( 1.0f, 1.0f, 1.0f ) },
//        { XMFLOAT3( -1.0f, 1.0f, 1.0f ) },
//        { XMFLOAT3( -1.0f, -1.0f, -1.0f ) },
//        { XMFLOAT3( 1.0f, -1.0f, -1.0f ) },
//        { XMFLOAT3( 1.0f, -1.0f, 1.0f ) },
//        { XMFLOAT3( -1.0f, -1.0f, 1.0f ) },
//    };
//    D3D11_BUFFER_DESC bd;
//	ZeroMemory( &bd, sizeof(bd) );
//    bd.Usage = D3D11_USAGE_DEFAULT;
//    bd.ByteWidth = sizeof( SimpleVertex ) * 8;
//    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
//	bd.CPUAccessFlags = 0;
//    D3D11_SUBRESOURCE_DATA InitData;
//	ZeroMemory( &InitData, sizeof(InitData) );
//    InitData.pSysMem = vertices;
//	SendMessage(MSG_CREATE_BUFFER,AuxGroupArgus( &bd, &InitData, &g_pVertexBuffer) );
//
//    // Set vertex buffer
//    UINT stride = sizeof( SimpleVertex );
//    UINT offset = 0;
//	m_deviceContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
//
//    // Create index buffer
//    WORD indices[] =
//    {
//        3,1,0,
//        2,1,3,
//
//        0,5,4,
//        1,5,0,
//
//        3,4,7,
//        0,4,3,
//
//        1,6,5,
//        2,6,1,
//
//        2,7,6,
//        3,7,2,
//
//        6,4,5,
//        7,4,6,
//    };
//    bd.Usage = D3D11_USAGE_DEFAULT;
//    bd.ByteWidth = sizeof( WORD ) * 36;        // 36 vertices needed for 12 triangles in a triangle list
//    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
//	bd.CPUAccessFlags = 0;
//    InitData.pSysMem = indices;
//	SendMessage(MSG_CREATE_BUFFER,AuxGroupArgus( &bd, &InitData, &g_pIndexBuffer));
//
//    // Set index buffer
//    m_deviceContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
//
//    // Set primitive topology
//    m_deviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
//
//
//}